home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 16 / CU Amiga Magazine's Super CD-ROM 16 (1997-10-16)(EMAP Images)(GB)[!][issue 1997-11].iso / CUCD / Graphics / Ghostscript / source / zchar.c < prev    next >
C/C++ Source or Header  |  1997-07-25  |  18KB  |  655 lines

  1. /* Copyright (C) 1989, 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* zchar.c */
  20. /* Character operators */
  21. #include "ghost.h"
  22. #include "errors.h"
  23. #include "oper.h"
  24. #include "gsstruct.h"
  25. #include "gxarith.h"
  26. #include "gxfixed.h"
  27. #include "gxmatrix.h"            /* for ifont.h */
  28. #include "gxchar.h"            /* for stringwidth_flag */
  29. #include "gxdevice.h"            /* for gxfont.h */
  30. #include "gxfont.h"
  31. #include "gzpath.h"
  32. #include "gzstate.h"
  33. #include "dstack.h"            /* for stack depth */
  34. #include "estack.h"
  35. #include "ialloc.h"
  36. #include "ichar.h"
  37. #include "idict.h"
  38. #include "ifont.h"
  39. #include "igstate.h"
  40. #include "ilevel.h"
  41. #include "iname.h"
  42. #include "ipacked.h"
  43. #include "store.h"
  44.  
  45. /* Forward references */
  46. private bool map_glyph_to_char(P3(const ref *, const ref *, ref *));
  47. private int finish_show(P1(os_ptr));
  48. private int finish_stringwidth(P1(os_ptr));
  49. private int op_show_cleanup(P1(os_ptr));
  50. private int op_show_return_width(P3(os_ptr, uint, double *));
  51.  
  52. /* <string> show - */
  53. private int
  54. zshow(register os_ptr op)
  55. {    gs_show_enum *penum;
  56.     int code = op_show_setup(op, &penum);
  57.     if ( code != 0 )
  58.       return code;
  59.     if ( (code = gs_show_n_init(penum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
  60.        {    ifree_object(penum, "op_show_enum_setup");
  61.         return code;
  62.        }
  63.     op_show_finish_setup(penum, 1, finish_show);
  64.     return op_show_continue(op - 1);
  65. }
  66.  
  67. /* <ax> <ay> <string> ashow - */
  68. private int
  69. zashow(register os_ptr op)
  70. {    gs_show_enum *penum;
  71.     int code;
  72.     double axy[2];
  73.  
  74.     if (    (code = num_params(op - 1, 2, axy)) < 0 ||
  75.         (code = op_show_setup(op, &penum)) != 0
  76.        )
  77.         return code;
  78.     if ( (code = gs_ashow_n_init(penum, igs, axy[0], axy[1], (char *)op->value.bytes, r_size(op))) < 0 )
  79.        {    ifree_object(penum, "op_show_enum_setup");
  80.         return code;
  81.        }
  82.     op_show_finish_setup(penum, 3, finish_show);
  83.     return op_show_continue(op - 3);
  84. }
  85.  
  86. /* <cx> <cy> <char> <string> widthshow - */
  87. private int
  88. zwidthshow(register os_ptr op)
  89. {    gs_show_enum *penum;
  90.     int code;
  91.     double cxy[2];
  92.  
  93.     check_type(op[-1], t_integer);
  94.     if ( (gs_char)(op[-1].value.intval) != op[-1].value.intval )
  95.         return_error(e_rangecheck);
  96.     if (    (code = num_params(op - 2, 2, cxy)) < 0 ||
  97.         (code = op_show_setup(op, &penum)) != 0
  98.        )
  99.         return code;
  100.     if ( (code = gs_widthshow_n_init(penum, igs, cxy[0], cxy[1],
  101.                      (gs_char)op[-1].value.intval,
  102.                      (char *)op->value.bytes,
  103.                      r_size(op))) < 0 )
  104.        {    ifree_object(penum, "op_show_enum_setup");
  105.         return code;
  106.        }
  107.     op_show_finish_setup(penum, 4, finish_show);
  108.     return op_show_continue(op - 4);
  109. }
  110.  
  111. /* <cx> <cy> <char> <ax> <ay> <string> awidthshow - */
  112. private int
  113. zawidthshow(register os_ptr op)
  114. {    gs_show_enum *penum;
  115.     int code;
  116.     double cxy[2], axy[2];
  117.  
  118.     check_type(op[-3], t_integer);
  119.     if ( (gs_char)(op[-3].value.intval) != op[-3].value.intval )
  120.         return_error(e_rangecheck);
  121.     if (    (code = num_params(op - 4, 2, cxy)) < 0 ||
  122.         (code = num_params(op - 1, 2, axy)) < 0 ||
  123.         (code = op_show_setup(op, &penum)) != 0
  124.        )
  125.         return code;
  126.     if ( (code = gs_awidthshow_n_init(penum, igs, cxy[0], cxy[1],
  127.                       (gs_char)op[-3].value.intval,
  128.                       axy[0], axy[1],
  129.                       (char *)op->value.bytes,
  130.                       r_size(op))) < 0 )
  131.        {    ifree_object(penum, "op_show_enum_setup");
  132.         return code;
  133.        }
  134.     op_show_finish_setup(penum, 6, finish_show);
  135.     return op_show_continue(op - 6);
  136. }
  137.  
  138. /* <proc> <string> kshow - */
  139. private int
  140. zkshow(register os_ptr op)
  141. {    gs_show_enum *penum;
  142.     int code;
  143.     check_proc(op[-1]);
  144.     if ( (code = op_show_setup(op, &penum)) != 0 )
  145.       return code;
  146.     if ( (code = gs_kshow_n_init(penum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
  147.        {    ifree_object(penum, "op_show_enum_setup");
  148.         return code;
  149.        }
  150.     op_show_finish_setup(penum, 2, finish_show);
  151.     sslot = op[-1];        /* save kerning proc */
  152.     return op_show_continue(op - 2);
  153. }
  154.  
  155. /* Common finish procedure for all show operations. */
  156. /* Doesn't have to do anything. */
  157. private int
  158. finish_show(os_ptr op)
  159. {    return 0;
  160. }
  161.  
  162. /* <string> stringwidth <wx> <wy> */
  163. private int
  164. zstringwidth(register os_ptr op)
  165. {    gs_show_enum *penum;
  166.     int code = op_show_setup(op, &penum);
  167.     if ( code != 0 )
  168.       return code;
  169.     if ( (code = gs_stringwidth_n_init(penum, igs, (char *)op->value.bytes, r_size(op))) < 0 )
  170.        {    ifree_object(penum, "op_show_enum_setup");
  171.         return code;
  172.        }
  173.     op_show_finish_setup(penum, 1, finish_stringwidth);
  174.     return op_show_continue(op - 1);
  175. }
  176. /* Finishing procedure for stringwidth. */
  177. /* Pushes the accumulated width. */
  178. private int
  179. finish_stringwidth(register os_ptr op)
  180. {    gs_point width;
  181.     gs_show_width(senum, &width);
  182.     push(2);
  183.     make_real(op - 1, width.x);
  184.     make_real(op, width.y);
  185.     return 0;
  186. }
  187.  
  188. /* Common code for charpath and .charboxpath. */
  189. private int
  190. zchar_path(register os_ptr op,
  191.   int (*init)(P5(gs_show_enum *, gs_state *, const char *, uint, bool)))
  192. {    gs_show_enum *penum;
  193.     int code;
  194.     check_type(*op, t_boolean);
  195.     code = op_show_setup(op - 1, &penum);
  196.     if ( code != 0 )
  197.       return code;
  198.     if ( (code = (*init)(penum, igs, (char *)op[-1].value.bytes, r_size(op - 1), op->value.boolval)) < 0 )
  199.        {    ifree_object(penum, "op_show_enum_setup");
  200.         return code;
  201.        }
  202.     op_show_finish_setup(penum, 2, finish_show);
  203.     return op_show_continue(op - 2);
  204. }
  205. /* <string> <outline_bool> charpath - */
  206. private int
  207. zcharpath(register os_ptr op)
  208. {    return zchar_path(op, gs_charpath_n_init);
  209. }
  210. /* <string> <box_bool> .charboxpath - */
  211. private int
  212. zcharboxpath(register os_ptr op)
  213. {    return zchar_path(op, gs_charboxpath_n_init);
  214. }
  215.  
  216. /* <wx> <wy> <llx> <lly> <urx> <ury> setcachedevice - */
  217. int
  218. zsetcachedevice(register os_ptr op)
  219. {    double wbox[6];
  220.  
  221.     gs_show_enum *penum = op_show_find();
  222.     int code = num_params(op, 6, wbox);
  223.     if ( penum == 0 )
  224.       return_error(e_undefined);
  225.     if ( code < 0 )
  226.       return code;
  227.     if ( gs_show_width_only(penum) )
  228.       return op_show_return_width(op, 6, &wbox[0]);
  229.     code = gs_setcachedevice_double(penum, igs, wbox);
  230.     if ( code < 0 )
  231.       return code;
  232.     pop(6);
  233.     if ( code == 1 )
  234.       clear_pagedevice(istate);
  235.     return 0;
  236. }
  237.  
  238. /* <w0x> <w0y> <llx> <lly> <urx> <ury> <w1x> <w1y> <vx> <vy> setcachedevice2 - */
  239. int
  240. zsetcachedevice2(os_ptr op)
  241. {    double wbox[10];
  242.     gs_show_enum *penum = op_show_find();
  243.     int code = num_params(op, 10, wbox);
  244.  
  245.     if ( penum == 0 )
  246.       return_error(e_undefined);
  247.     if ( code < 0 )
  248.       return code;
  249.     if ( gs_show_width_only(penum) )
  250.       return op_show_return_width(op, 10,
  251.                       (gs_rootfont(igs)->WMode ?
  252.                        &wbox[6] : &wbox[0]));
  253.     code = gs_setcachedevice2_double(penum, igs, wbox);
  254.     if ( code < 0 )
  255.       return code;
  256.     pop(10);
  257.     if ( code == 1 )
  258.       clear_pagedevice(istate);
  259.     return 0;
  260. }
  261.  
  262. /* <wx> <wy> setcharwidth - */
  263. private int
  264. zsetcharwidth(register os_ptr op)
  265. {    double width[2];
  266.     gs_show_enum *penum = op_show_find();
  267.     int code = num_params(op, 2, width);
  268.  
  269.     if ( penum == 0 )
  270.       return_error(e_undefined);
  271.     if ( code < 0 )
  272.       return code;
  273.     if ( gs_show_width_only(penum) )
  274.       return op_show_return_width(op, 2, &width[0]);
  275.     code = gs_setcharwidth(penum, igs, width[0], width[1]);
  276.     if ( code < 0 )
  277.       return code;
  278.     pop(2);
  279.     return 0;
  280. }
  281.  
  282. /* <dict> .fontbbox <llx> <lly> <urx> <ury> -true- */
  283. /* <dict> .fontbbox -false- */
  284. private int
  285. zfontbbox(register os_ptr op)
  286. {    double bbox[4];
  287.     int code;
  288.  
  289.     check_type(*op, t_dictionary);
  290.     check_dict_read(*op);
  291.     code = font_bbox_param(op, bbox);
  292.     if ( code < 0 )
  293.       return code;
  294.     if ( bbox[0] < bbox[2] && bbox[1] < bbox[3] )
  295.     {    push(4);
  296.         make_reals(op - 4, bbox, 4);
  297.         make_true(op);
  298.     }
  299.     else
  300.     {    /* No bbox, or an empty one. */
  301.         make_false(op);
  302.     }
  303.     return 0;
  304. }
  305.  
  306. /* ------ Initialization procedure ------ */
  307.  
  308. BEGIN_OP_DEFS(zchar_op_defs) {
  309.     {"3ashow", zashow},
  310.     {"6awidthshow", zawidthshow},
  311.     {"2charpath", zcharpath},
  312.     {"2.charboxpath", zcharboxpath},
  313.     {"2kshow", zkshow},
  314.     {"6setcachedevice", zsetcachedevice},
  315.     {":setcachedevice2", zsetcachedevice2},
  316.     {"2setcharwidth", zsetcharwidth},
  317.     {"1show", zshow},
  318.     {"1stringwidth", zstringwidth},
  319.     {"4widthshow", zwidthshow},
  320.         /* Extensions */
  321.     {"1.fontbbox", zfontbbox},
  322.         /* Internal operators */
  323.     {"0%finish_show", finish_show},
  324.     {"0%finish_stringwidth", finish_stringwidth},
  325.     {"0%op_show_continue", op_show_continue},
  326. END_OP_DEFS(0) }
  327.  
  328. /* ------ Subroutines ------ */
  329.  
  330. /* Most of these are exported for zchar2.c. */ 
  331.  
  332. /* Convert a glyph to a ref. */
  333. private void
  334. glyph_ref(gs_glyph glyph, ref *gref)
  335. {    if ( glyph < gs_min_cid_glyph )
  336.       name_index_ref(glyph, gref);
  337.     else
  338.       make_int(gref, glyph - gs_min_cid_glyph);
  339. }
  340.  
  341. /* Prepare to set up for a show operator. */
  342. /* Don't change any state yet. */
  343. int
  344. op_show_setup(os_ptr op, gs_show_enum **ppenum)
  345. {    check_read_type(*op, t_string);
  346.     return op_show_enum_setup(op, ppenum);
  347. }
  348. int
  349. op_show_enum_setup(os_ptr op, gs_show_enum **ppenum)
  350. {    /* Provide a special "hook" for an unusual application */
  351.     /* that needs to be able to intervene before any operator */
  352.     /* that renders or measures characters. */
  353. #ifdef OP_SHOW_ENUM_SETUP_HOOK
  354.     OP_SHOW_ENUM_SETUP_HOOK
  355. #endif
  356.     check_estack(snumpush + 2);
  357.     if ( (*ppenum = gs_show_enum_alloc((gs_memory_t *)imemory, igs, "op_show_enum_setup")) == 0 )
  358.       return_error(e_VMerror);
  359.     return 0;
  360. }
  361.  
  362. /* Finish setting up a show operator.  This can't fail, since */
  363. /* op_show_enum_setup did the check_estack. */
  364. void
  365. op_show_finish_setup(gs_show_enum *penum, int npop, op_proc_p endproc /* end procedure */)
  366. {    register es_ptr ep = esp + snumpush;
  367.     esp = ep;
  368.     make_mark_estack(ep - (snumpush - 1), es_show, op_show_cleanup);
  369.     if ( endproc == NULL )
  370.       endproc = finish_show;
  371.     make_null(&esslot(ep));
  372.     make_int(&essindex(ep), 0);
  373.     make_int(&esodepth(ep), 0);    /* see gs_show_render case in */
  374.                     /* op_show_continue_dispatch */
  375.     make_int(&esddepth(ep), 0);    /* ditto */
  376.     make_int(&esgslevel(ep), igs->level);
  377.     make_op_estack(&eseproc(ep), endproc);
  378.     make_istruct(ep, 0, penum);
  379. }
  380.  
  381. /* Continuation operator for character rendering. */
  382. int
  383. op_show_continue(os_ptr op)
  384. {    return op_show_continue_dispatch(op, gs_show_next(senum));
  385. }
  386. /* Note that this sets osp = op explicitly iff the dispatch succeeds. */
  387. /* This is so that the show operators don't pop anything from the o-stack */
  388. /* if they don't succeed. */
  389. /* Note also that if it returns an error, it has freed the enumerator. */
  390. int
  391. op_show_continue_dispatch(register os_ptr op, int code)
  392. {    gs_show_enum *penum = senum;
  393.     switch ( code )
  394.     {
  395.     case 0:                /* all done */
  396.     {    os_ptr save_osp = osp;
  397.         osp = op;
  398.         code = (*real_opproc(&seproc))(op);
  399.         op_show_free(code);
  400.         if ( code < 0 )
  401.         {    osp = save_osp;
  402.             return code;
  403.         }
  404.         return o_pop_estack;
  405.     }
  406.     case gs_show_kern:
  407.     {    ref *pslot = &sslot;
  408.         push(2);
  409.         make_int(op - 1, gs_kshow_previous_char(penum));
  410.         make_int(op, gs_kshow_next_char(penum));
  411.         push_op_estack(op_show_continue);        /* continue after kerning */
  412.         *++esp = *pslot;    /* kerning procedure */
  413.     }
  414.         return o_push_estack;
  415.     case gs_show_render:
  416.     {    gs_font *pfont = gs_currentfont(igs);
  417.         font_data *pfdata = pfont_data(pfont);
  418.         gs_char chr = gs_show_current_char(penum);
  419.         gs_glyph glyph = gs_show_current_glyph(penum);
  420.         push(2);
  421.         op[-1] = pfdata->dict;    /* push the font */
  422.         /*
  423.          * For Type 1 and Type 4 fonts, prefer BuildChar to
  424.          * BuildGlyph, so that PostScript procedures appearing in the
  425.          * CharStrings dictionary will receive the character code
  426.          * rather than the character name; for Type 3 fonts,
  427.          * prefer BuildGlyph to BuildChar.
  428.          */
  429.         if ( pfont->FontType == ft_user_defined )
  430.         {    /* Type 3 font, prefer BuildGlyph. */
  431.             if ( level2_enabled &&
  432.                  !r_has_type(&pfdata->BuildGlyph, t_null) &&
  433.                  glyph != gs_no_glyph
  434.                )
  435.             {    glyph_ref(glyph, op);
  436.                 esp[2] = pfdata->BuildGlyph;
  437.             }
  438.             else if ( r_has_type(&pfdata->BuildChar, t_null) )
  439.                 goto err;
  440.             else if ( chr == gs_no_char )
  441.               {    /* glyphshow, reverse map the character */
  442.                 /* through the Encoding */
  443.                 ref gref;
  444.                 const ref *pencoding = &pfdata->Encoding;
  445.  
  446.                 glyph_ref(glyph, &gref);
  447.                 if ( !map_glyph_to_char(&gref, pencoding,
  448.                             (ref *)op)
  449.                    )
  450.                   {    /* Not found, try .notdef */
  451.                     name_enter_string(".notdef", &gref);
  452.                     if ( !map_glyph_to_char(&gref,
  453.                                 pencoding,
  454.                                 (ref *)op)
  455.                        )
  456.                       goto err;
  457.                   }
  458.                 esp[2] = pfdata->BuildChar;
  459.               }
  460.             else
  461.             {    make_int(op, chr);
  462.                 esp[2] = pfdata->BuildChar;
  463.             }
  464.         }
  465.         else
  466.         {    /* Type 1 or Type 4 font, prefer BuildChar. */
  467.             /* We know that both BuildChar and BuildGlyph */
  468.             /* are present. */
  469.             if ( chr != gs_no_char )
  470.             {    make_int(op, chr);
  471.                 esp[2] = pfdata->BuildChar;
  472.             }
  473.             else
  474.             {    glyph_ref(glyph, op);
  475.                 esp[2] = pfdata->BuildGlyph;
  476.             }
  477.         }
  478.         /* Save the stack depths in case we bail out. */
  479.         sodepth.value.intval = ref_stack_count(&o_stack) - 2;
  480.         sddepth.value.intval = ref_stack_count(&d_stack);
  481.         push_op_estack(op_show_continue);
  482.         ++esp;        /* skip BuildChar or BuildGlyph proc */
  483.     }
  484.         return o_push_estack;
  485.     default:            /* error */
  486. err:        if ( code >= 0 )
  487.           code = gs_note_error(e_invalidfont);
  488.         return op_show_free(code);
  489.     }
  490. }
  491. /* Reverse-map a glyph name to a character code for glyphshow. */
  492. private bool
  493. map_glyph_to_char(const ref *pgref, const ref *pencoding, ref *pch)
  494. {    uint esize = r_size(pencoding);
  495.     uint ch;
  496.     ref eref;
  497.     for ( ch = 0; ch < esize; ch++ )
  498.       {    array_get(pencoding, (long)ch, &eref);
  499.         if ( obj_eq(pgref, &eref) )
  500.           { make_int(pch, ch);
  501.             return true;
  502.           }
  503.       }
  504.     return false;
  505. }
  506.  
  507. /* Find the index of the e-stack mark for the current show enumerator. */
  508. /* Return 0 if we can't find the mark. */
  509. uint
  510. op_show_find_index(void)
  511. {    uint count = 0;
  512.     STACK_LOOP_BEGIN(&e_stack, ep, size)
  513.       for ( ep += size - 1; size != 0; size--, ep--, count++ )
  514.         if ( r_is_estack_mark(ep) && estack_mark_index(ep) == es_show )
  515.           return count;
  516.     STACK_LOOP_END(ep, size)
  517.     return 0;            /* no mark */
  518. }
  519.  
  520. /* Find the current show enumerator on the e-stack. */
  521. gs_show_enum *
  522. op_show_find(void)
  523. {    uint index = op_show_find_index();
  524.     if ( index == 0 )
  525.       return 0;            /* no mark */
  526.     return r_ptr(ref_stack_index(&e_stack, index - (snumpush - 1)),
  527.              gs_show_enum);
  528. }
  529.  
  530. /* Shortcut the BuildChar or BuildGlyph procedure at the point */
  531. /* of the setcharwidth or the setcachedevice[2] if we are in */
  532. /* a stringwidth or cshow, or if we are only collecting the scalable */
  533. /* width for an xfont character. */
  534. private int
  535. op_show_return_width(os_ptr op, uint npop, double *pwidth)
  536. {    uint index = op_show_find_index();
  537.     es_ptr ep = (es_ptr)ref_stack_index(&e_stack, index - (snumpush - 1));
  538.     int code = gs_setcharwidth(esenum(ep), igs, pwidth[0], pwidth[1]);
  539.     uint ocount, dsaved, dcount;
  540.  
  541.     if ( code < 0 )
  542.       return code;
  543.     /* Restore the operand and dictionary stacks. */
  544.     ocount = ref_stack_count(&o_stack) - (uint)esodepth(ep).value.intval;
  545.     if ( ocount < npop )
  546.       return_error(e_stackunderflow);
  547.     dsaved = (uint)esddepth(ep).value.intval;
  548.     dcount = ref_stack_count(&d_stack);
  549.     if ( dcount < dsaved )
  550.       return_error(e_dictstackunderflow);
  551.     while ( dcount > dsaved )
  552.       {    code = zend(op);
  553.         if ( code < 0 )
  554.           return code;
  555.         dcount--;
  556.       }
  557.     ref_stack_pop(&o_stack, ocount);
  558.     /* We don't want to pop the mark or the continuation */
  559.     /* procedure (op_show_continue or cshow_continue). */
  560.     pop_estack(index - snumpush);
  561.     return o_pop_estack;
  562. }
  563.  
  564. /*
  565.  * Restore state after finishing, or unwinding from an error within, a show
  566.  * operation.  Note that we assume op == osp, and may reset osp.
  567.  */
  568. private int
  569. op_show_restore(bool for_error)
  570. {    register es_ptr ep = esp + snumpush;
  571.     gs_show_enum *penum = esenum(ep);
  572.     int saved_level = esgslevel(ep).value.intval;
  573.     int code = 0;
  574.  
  575.     if ( for_error )
  576.       { uint saved_count = esodepth(ep).value.intval;
  577.         uint count = ref_stack_count(&o_stack);
  578.  
  579.         if ( count > saved_count ) /* if <, we're in trouble */
  580.           ref_stack_pop(&o_stack, count - saved_count);
  581.       }
  582.     if ( penum->stringwidth_flag == 1 )
  583.       { /* stringwidth does an extra gsave */
  584.         --saved_level;
  585.       }
  586.     while ( igs->level > saved_level && code >= 0 )
  587.       { if ( igs->saved == 0 || igs->saved->saved == 0 )
  588.           { /*
  589.          * Bad news: we got an error inside a save inside a
  590.          * BuildChar or BuildGlyph.  Don't attempt to recover.
  591.          */
  592.         code = gs_note_error(e_Fatal);
  593.           }
  594.         else
  595.           code = gs_grestore(igs);
  596.       }
  597.     gs_show_enum_release(penum, (gs_memory_t *)imemory);
  598.     return code;
  599. }
  600. /* Clean up after an error. */
  601. private int
  602. op_show_cleanup(os_ptr op)
  603. {    return op_show_restore(true);
  604. }
  605. /* Clean up after termination of a show operation. */
  606. int
  607. op_show_free(int code)
  608. {    int rcode;
  609.     esp -= snumpush;
  610.     rcode = op_show_restore(code < 0);
  611.     return (rcode < 0 ? rcode : code);
  612. }
  613.  
  614. /* Get a FontBBox parameter from a font dictionary. */
  615. int
  616. font_bbox_param(const ref *pfdict, double bbox[4])
  617. {    ref *pbbox;
  618.     /*
  619.      * Pre-clear the bbox in case it's invalid.  The Red Books say that
  620.      * FontBBox is required, but the Adobe interpreters don't require
  621.      * it, and a few user-written fonts don't supply it, or supply one
  622.      * of the wrong size (!); also, PageMaker 5.0 (an Adobe product!)
  623.      * sometimes emits an absurd bbox for Type 1 fonts converted from
  624.      * TrueType.
  625.      */
  626.     bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0.0;
  627.     if ( dict_find_string(pfdict, "FontBBox", &pbbox) > 0 )
  628.     {    if ( !r_is_array(pbbox) )
  629.           return_error(e_typecheck);
  630.         if ( r_size(pbbox) == 4 )
  631.         {    const ref_packed *pbe = pbbox->value.packed;
  632.             ref rbe[4];
  633.             int i;
  634.             int code;
  635.             float dx, dy, ratio;
  636.  
  637.             for ( i = 0; i < 4; i++ )
  638.               {    packed_get(pbe, rbe + i);
  639.                 pbe = packed_next(pbe);
  640.               }
  641.             if ( (code = num_params(rbe + 3, 4, bbox)) < 0 )
  642.               return code;
  643.             /* Require "reasonable" values.  Thanks to Ray */
  644.             /* Johnston for suggesting the following test. */
  645.             dx = bbox[2] - bbox[0];
  646.             dy = bbox[3] - bbox[1];
  647.             if ( dx <= 0 || dy <= 0 ||
  648.                  (ratio = dy / dx) < 0.125 || ratio > 8.0
  649.                )
  650.               bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0.0;
  651.         }
  652.     }
  653.     return 0;
  654. }
  655.